#pragma once
#ifndef Obj_h__
#define Obj_h__

#include "Common.h"
#include "Geo.h"
#include "Gfx.h"

#include <eastl/vector.h>
#include <eastl/set.h>
#include <eastl/map.h>
#include <eastl/string.h>

struct Obj;

struct Prop
{
	bool Truth;
	double Number;
	eastl::string String;
	Vec Position;
	Obj* Object;

	Prop() : Truth(false), Number(0), Position(0,0), Object(0) {}

	Prop(bool t) : Truth(t) {}
	Prop(double n) : Number(n) {}
	Prop(const eastl::string& str) : String(str) {}
	Prop(const char* str) : String(str) {}
	Prop(const Vec& p) : Position(p) {}
	Prop(Obj* p) : Object(p) {}
};

struct World
{
	eastl::vector<Obj*> Objects;
	eastl::map<int, Prop> Props;
	eastl::set<uint64> Collisions;
	bool Paused;
	bool DoCollisions;
	bool DoMouseEvents;

	World();
	~World();

	Vec RenderOffset;

	void Update(float dt);
	void Render();

	Obj* GetObjectAt(const Vec& pos);
	void GetObjectsAt(const Vec& pos, eastl::vector<Obj*>& objects);

	Obj* AddToWorld(Obj* obj);
	Obj* AddToWorld(Obj* obj, const Vec& pos);
	Obj* RemoveFromWorld(Obj* obj);
	bool InWorld(const Obj* obj);

	size_t CountObjects(int of_type = 0);

	void KillAll();

	Vec ToWorldVec(const Vec& pos) const
	{
		return pos-RenderOffset;
	}

	void BroadcastEvent(int event, const Prop& arg, int type = 0);

	void AddCollision(uint type1, uint type2);
	void RemoveCollision(uint type1, uint type2);

private:

	void DoMouse();

	Obj* mMouseOverObject;
	Obj* mMouseDownObject;
};

enum {
	WRL_ADDED, WRL_REMOVED,
	MEV_OVER, MEV_OUT, MEV_CLICK, MEV_DOWN, MEV_UP,
	EV_TIMER,
	EV_CUSTOM,
};

struct Obj
{
	Vec Pos;
	Vec Vel;
	Vec Size;
	float Radius;
	Pic Img;
	float Friction;
	float Rot;

	int CollisionGroup;
	static const int NO_COLLISION = 0;

	double Life;

	World* Wrld;

	eastl::map<int, double> Timers;
	double GetTimer(int timer);
	void SetTimer(int timer, double time);

	/// Bitmask
	uint32_t RenderInPasses;

	bool Dead;
	bool Circular;

	Obj() : Pos(0,0), Vel(0,0), Size(1,1), Radius(1), Circular(false), Dead(false), CollisionGroup(NO_COLLISION), Life(0), Wrld(0), Img(0), Friction(0.0f), Rot(0), RenderInPasses(0x1) {}
	virtual ~Obj() {}

	virtual int Type() { return 'Obj'; }

	virtual void Update(float dt);
	virtual void Render(const Vec& offset);
	virtual void Collide(Obj& other, bool first);
	virtual void Event(int event, const Prop& arg);

	Vec GetCenter()
	{
		if (Circular) return Pos;
		return Pos+Size/2;
	}

	bool IntersectsSquare(const Obj& other)
	{
		Vec P2 = Pos+Size;
		Vec otherP2 = other.Pos+other.Size;
		return (P2.X > other.Pos.X)&&(Pos.X < otherP2.X)&&(P2.Y > other.Pos.Y)&&(Pos.Y < otherP2.Y);
	}

	bool IntersectPoint(const Vec& pt)
	{
		if (Circular)
		{
			return VecInCircle(Pos, Radius, pt);
		}
		else
		{
			Vec P2 = Pos+Size;
			return (P2.X > pt.X) && (Pos.X <= pt.X) && (P2.Y > pt.Y) && (Pos.Y <= pt.Y);
		}
	}

	bool IntersectsRadius(const Obj& other)
	{
		return VecInCircle(Pos, Radius+other.Radius, other.Pos);
	}
};

#endif // Obj_h__
